Generally described, software applications include executable code to implement various processes associated with the software application. It is common for applications to implement single processes as multiple sub-processes, often referred to as threads of control. For example, a web browser might have one thread display images or text while another thread retrieves data from the network. In another example, a word processor may have a thread for displaying graphics, another thread for responding to user keystrokes, and a third thread for performing spelling and grammar checking in the background.
In certain situations, a single application may be required to perform several similar tasks, for example, a web server accepts client requests for web pages, images, sound, and so forth. A busy web server may have several (perhaps thousands of) clients concurrently accessing it. If the web server were to run as a traditional single-thread process, it would be able to service only one client at a time, and clients might have to wait unacceptably long times for their requests to be serviced. It is generally more efficient to use one process that contains multiple threads. Illustratively, in a multithreaded web server process, the server can create a separate thread to listen for client requests. When a client request is detected, the server can create a new thread to service the client request, and the first thread can resume listening for additional client requests.
There are several advantages to using multithread programming. Multithreading an interactive application may allow a program to continue running even if part of it is blocked or is performing a lengthy operation, thereby increasing responsiveness to the user. For example, a multithreaded web browser could allow user interaction in one thread while an image is being loaded in another thread. Threads share the memory and resources of the process to which they belong. The benefit of sharing code and data is that it allows an application to have several different threads of activity executing within the same address space. Allocating memory and resources for process creation can be costly. Since threads share the resources of the process to which they belong, it is more efficient to create and context-shift threads than it is to create new processes.
Processes that execute in a multithreaded execution environment are also susceptible to experiencing concurrency errors that can occur when multiple threads of a process execute independently (as opposed to sequentially) as asynchronous tasks. For example, a multithread process can execute portions of the process in a first thread in a sequence relative to the execution of a portion of the process in a second thread, where the first thread sets a variable to a value that causes the second thread to crash. Debuggers can provide useful information relating to the crashed second thread, such as the position in the program at which it crashed. But the first thread, whose action caused or contributed to the crash of the second thread, continues to execute, and the state of the first thread at the time of the second thread's crash is typically not available for capture. The lack of visibility into the first thread's execution state around the time that the second thread crashed makes it difficult to determine the cause of the second thread's crash. For debugging purposes, it is desirable to determine the source of the asynchronous task that crashed; however, the thread that originated the crashed asynchronous task may have terminated already, or it may have returned from the function that created the asynchronous task that crashed, thereby making it difficult to determine the cause of the crash. Moreover, crashes resulting from the interaction of a greater number of threads executing portions of a single process concurrently can present a greater challenge to identify the root cause of the crash.